﻿#define _CRT_SECURE_NO_WARNINGS 1
//const修饰变量
//#include <stdio.h>
//
//int main()
//{
//	//int a = 0;
//	const int a = 0;
//	//a = 100; //err ，const修饰变量后，变量具有了常属性，无法被更改，称为常变量
//	printf("%d\n", a);
//
//	return 0;
//}

//const 修饰指针
//1. const在*的左边
//2. const在*的右边

//#include <stdio.h>
//
//int main()
//{
//	int a = 10;
//	int b = 0;
//	const int* pa1 = &a;
//	//*pa1 = 100;//在*左边加上const，被修饰的指针指向的内容无法被修改, 
//	//pa1 = &b;//但指针变量存储的地址可以被修改
//
//	int* const pa2 = &a;
//	*pa2 = 100;//在*右边加上const，被修饰的指针指向的内容可以被修改, 
//	pa2 = &b;//err ,但指针变量存储的地址无法被修改
//
//	return 0;
//}

//野指针和避免方法
//#include<stdio.h>
//
//int* test()
//{
//	int n = 1;
//	n++;
//	return &n;
//}
//
//int main()
//{
//	//定义指针变量时不给这个指针变量初始化，被解引用时那么就非法访问不属于程序的空间了
//	int* p1;
//	//解决方法就是: 在定义指针变量时，如果不知道要初始化成什么，那么就初始化为NULL
//	int* p2 = NULL;
//
//	//指针越界访问，也是野指针
//	int arr[10] = { 0 };
//	int i = 0;
//	for (i = 0; i <= 11; i++)
//	{
//		printf("%d ", arr[i]);//当i大于9时，此时再用arr[i]进行访问就越界了(非法访问)
//	}
//	//解决方法就是在写循环的过程中注意控制循环的终止条件
//
//	//指针指向的空间释放
//	int* p = test();
//	//到这里时，test函数里的n变量是一个临时变量
//	//临时变量出了作用域就会被销毁(被操作系统回收了)
//	printf("%d\n", *p);//err， 这里再访问就成野指针进行非法访问了
//	//解决方法就是：尽量不要返回局部变量的地址
//
//	return 0;
//}

//assert 断⾔
//#include<stdio.h>
//#include<assert.h>
//
//void Print(int* arr, int sz)
//{
//	//arr传过来的有可能是一个NULL指针，那么下面再进行访问就是非法访问内存了
//	//所以用assert进行断言一下是否为空, 为空就终止程序,否则就继续执行
//	assert(arr != NULL);
//
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");
//}
//
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	Print(arr, sz);
//	Print(NULL, sz);//err， arrert会终止程序的运行
//
//	return 0;
//}

//指针的使⽤
//strlen的模拟实现

#include<stdio.h>
#include<string.h>
#include <assert.h>

//指针-指针的方式实现
//size_t my_strlen(char* str)
//{
//	char* former = str;
//	while (*str != '\0')
//	{
//		str++;
//	}
//
//	return str - former;
//}

//循环的方式实现
//size_t my_strlen(char* str)
//{
//	assert(str != '\0');
//
//	size_t count = 0;
//	while (*str != '\0')
//	{
//		count++;
//		str++;
//	}
//
//	return count;
//}
//
//
//int main()
//{
//	char str[] = "abcdef";
//	size_t sz1 = strlen(str);
//	size_t sz2 = my_strlen(str);
//
//	printf("%zd\n", sz1);
//	printf("%zd\n", sz2);
//
//	return 0;
//}

//传值调⽤和传址调⽤
//写⼀个函数，交换两个整型变量的值
//#include<stdio.h>
//
////void Swap(int x, int y)
////{
////	int z = x;
////	x = y;
////	y = z;
////}
//
//void Swap(int* pa, int* pb)
//{
//	int z = *pa;
//	*pa = *pb;
//	*pb = z;
//}
//
//int main()
//{
//	int a = 10;
//	int b = 20;
//	printf("交换前: a=%d b=%d\n", a, b);
//
//	//Swap(a,b);//err ，传值调用改变形参不影响实参
//	Swap(&a, &b);//传址调用
//
//	printf("交换后: a=%d b=%d\n", a, b);
//
//
//	return 0;
//}

//数组名的理解
//数组名就是数组的首元素地址,但有两个例外情况
//1. sizeof(数组名)，计算的是整个数组的大小
//2. &数组名，取的是整个数组的地址
//#include<stdio.h>
//
//int main()
//{
//	int arr[10] = { 0 };
//
//	printf("arr[0]   = %p\n", arr[0]);//数组的首元素地址
//	printf("arr[0]+1 = %p\n", arr[0]+1);//+1跳过四个字节(一个int类型的大小)
//
//	printf("arr      = %p\n", arr);//数组的首元素地址
//	printf("arr+1    = %p\n", arr+1);//+1跳过四个字节(一个int类型的大小)
//
//	printf("&arr     = %p\n", &arr);//整个数组的地址
//	printf("&arr+1   = %p\n", &arr+1);//+1跳过40个字节，也就是一个数组的大小
//
//	return 0;
//}

//使⽤指针访问数组
//#include<stdio.h>
//
////一维数组传参的本质就是传递数组的首元素地址
//void Print(int *p, int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		//printf("%d ", *p);
//		//printf("%d ", *(p+i));
//		//p++;
//
//		printf("%d ", p[i]); //*(p+i) == p[i]
//	}
//	printf("\n");
//}
//
//
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	Print(arr, sz);
//
//	return 0;
//}

//冒泡排序
//#include<stdio.h>

//void BubbleSort(int arr[], int sz)
//{
//	//趟数
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		int j = 0;
//		for (j = 0; j < sz - 1 - i; j++)//每趟的排序
//		{
//			if (arr[j] > arr[j+1])
//			{
//				int tmp = arr[j];
//				arr[j] = arr[j+1];
//				arr[j+1] = tmp;
//			}
//		}
//	}
//}

//优化
//void BubbleSort(int arr[], int sz)
//{
//	//趟数
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		int flag = 0;
//		int j = 0;
//		for (j = 0; j < sz - 1 - i; j++)//每趟的排序
//		{
//			if (arr[j] > arr[j + 1])
//			{
//				int tmp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;
//				flag = 1;
//			}
//		}
//
//		if (flag == 0)
//		{
//			break;
//		}
//	}
//}
//
//void Print_arr(int arr[], int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//
//	printf("\n");
//}
//
//int main()
//{
//	int arr[10] = { 3,5,1,4,2,7,9,6,8,0 };
//	//int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	Print_arr(arr, sz);
//	BubbleSort(arr, sz);
//	Print_arr(arr, sz);
//
//	return 0;
//}

//二级指针
//#include<stdio.h>
//
//int main()
//{
//	int a = 10;
//	int* pa = &a;//一级指针,int*：*表示pa是一个指针变量，int表示指向的是一个int类型
//	int** ppa = &pa;//二级指针,int* *：从右往左，第一个*表示ppa是一个指针变量，int*表示指向的是一个int*类型
//
//	**ppa = 100;//二级指针解引用，从右往左，第一个*表示解引用ppa这个指针变量，第二个*表示解引用*ppa所指向pa的指针变量
//	printf("%d\n", a);
//
//	return 0;
//}

//指针数组
//是一个数组，存储的是指针变量
//#include<stdio.h>
//
//int main()
//{
//	int a = 10;
//	int b = 20;
//	int c = 30;
//
//	int* arr[] = { &a, &b, &c };
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		printf("%d ", *(arr[i]));
//	}
//
//	return 0;
//}

//指针数组模拟⼆维数组
//#include<stdio.h>
//
//int main()
//{
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[] = { 2,3,4,5,6 };
//	int arr3[] = { 3,4,5,6,7 };
//
//	int* parr[] = { arr1, arr2, arr3 };
//
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		int j = 0;
//		for (j = 0; j < 5; j++)
//		{
//			//printf("%d ", *(*(parr+i)+j));
//			printf("%d ", parr[i][j]); //parr[i][j] == *(*(parr+i)+j))
//		}
//		printf("\n");
//	}
//
//	return 0;
//}

//字符指针变量
//#include<stdio.h>
//
//int main()
//{
//	char ch = 'w';
//	char* pc = &ch;
//
//	//这里的字符串是常量，本质是把字符串的首字符的地址给了str,
//	//既然字符串是常量那么就不能被更改，所以给指针变量也加上const
//	const char* str = "abcdef";
//	printf("%s\n", str);
//
//	while (*str != '\0')
//	{
//		printf("%c", *str);
//		str++;
//	}
//
//	return 0;
//}

//数组指针变量
//是一个指针，指向着一个数组
//#include<stdio.h>
//
//int main()
//{
//	int arr[10] = { 0 };
//
//	int* pa1 = &arr[0];//这是数组的首元素地址
//	int* pa2 = arr;//数组名是数组的首元素地址
//	int (*pa3) [10] =  &arr;//这就是整个数组的地址，也叫数组指针
//
//	//对数组指针的访问
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", (*pa3)[i]);//但实际数组指针不是这样用的，数组指针一般用于作函数的参数来接收一个一维数组的地址
//	}
//
//	return 0;
//}

//⼆维数组传参的本质
//本质就是传的是二维数组的首元素地址(二维数组的首元素是一个一维数组)
#include<stdio.h>

//void Print_arr(int arr[3][5], int r, int c)
//{
//	int i = 0;
//	for (i = 0; i < r; i++)
//	{
//		int j = 0;
//		for (j = 0; j < c; j++)
//		{
//			printf("%d ", arr[i][j]);
//		}
//		printf("\n");
//	}
//}

//二维数组传参的本质就是传首元素的地址，那么用数组指针也可以接收
void Print_arr(int (*parr)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			//printf("%d ", *(*(parr+i)+j));
			printf("%d ", parr[i][j]);//parr[i][j] == *(*(parr+i)+j)
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	Print_arr(arr, 3, 5);

	return 0;
}